<template>
  <div
    ref="threejsContainer"
    class="threejs-container w-full relative h-full flex justify-center items-center"
  >
    <div
      class="layer flex absolute bottom-8% left-50% transform -translate-x-50%"
    >
      <div
        class="flex items-center justify-center mx-3 flex-col"
        v-for="item in qiguanList"
        :key="item.id"
        @click="getQiguan(item.id)"
      >
        <div class="button-img w-16.5 h-16.5">
          <img
            :src="`/person/qiguan/${item.type}.png`"
            class="cursor-pointer w-full h-full object-cover"
            alt=""
          />
        </div>
      </div>
    </div>
    <div
      class="threejs-layer flex flex-col absolute w-77 h-65 pl-5 pr-2.5 py-5 box-border"
      ref="threejsLayer"
      v-if="isLayer"
    >
      <el-icon
        size="25px"
        color="#409efc"
        class="flex self-end cursor-pointer mr-2.5"
        @click="closeLayer"
        ><CircleClose
      /></el-icon>
      <div class="flex flex-col w-full box-border pl-2.5 pr-2.5">
        <div class="text-6 text-white mb-3.75">诊断信息</div>
        <div class="text-4 text-white">
          确诊为 肺癌 I 期，病灶位于 左肺中叶，靠近肺门区域。影像检查显示：
          病灶大小约 2.1 cm × 1.8 cm，呈不规则形状，边缘部分毛刺状。
          未见明显纵隔淋巴结肿大。 未见远处转移迹象。
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { nextTick, onMounted, onUnmounted, ref } from "vue";
import * as THREE from "three";
import { initThreeJS } from "@/three/threeInit";
import { loadModel } from "@/three/modelLoad";
import { startAnimation } from "@/three/animation";
import { setupPostProcessing } from "@/three/postprocessing";
import sunVertexShader from "@/assets/shaders/sun/vertex.glsl";
import sunFragmentShader from "@/assets/shaders/sun/fragment.glsl";
import { gsap } from "gsap";
import {
  bodyMaterial,
  RespiratoyMaterial,
  NervesMaterial,
  MammaryMaterial,
  LungsMaterial,
  SkeletalMaterial,
} from "@/three/material";
import { CircleClose } from "@element-plus/icons-vue";
const threejsContainer = ref(null);
const isMan = ref(false);
const isLayer = ref(false);
const isProgress = ref(true);
const progressValue = ref(0);
let scene,
  camera,
  renderer,
  personModel,
  controls,
  composer,
  LungsL,
  LungsR,
  sphere,
  sphereMatiral,
  diagonalLength,
  clock,
  LungGroup,
  animationFrameId;

let initialState = {};
//const gui = new GUI();
const threejsLayer = ref(null);
clock = new THREE.Clock(); // 用于时间计算
// 用于控制旋转的标志
let isRotating = true; // 初始状态为旋转状态
const qiguanList = ref([
  {
    id: 1,
    name: "肺部",
    type: "lung",
  },
  {
    id: 2,
    name: "乳腺",
    type: "ruxian",
  },
  {
    id: 3,
    name: "呼吸",
    type: "huxi",
  },
]);
const Animation = ref(false);
const getQiguan = async (id) => {
  if (id === 1) {
    Animation.value = !Animation.value; // 切换布尔值
    await nextTick();
    if (Animation.value) {
      isRotating = false;
      controls.enableZoom = false; // 禁用缩放
      controls.enableRotate = false;
      await goToFirst(1);
      await startAnimation(camera, personModel, LungGroup);
      isLayer.value = true;
      gsap.to(LungGroup.rotation, {
        duration: 3, // 旋转动画的持续时间
        y: 2 * Math.PI,
        ease: "linear", // 不使用缓动效果，保持匀速旋转
        repeat: -1, // 无限循环
        yoyo: false, // 不来回旋转
      });
    } else {
      isLayer.value = false;
      isRotating = true;
      controls.enableZoom = true; // 启用缩放
      controls.enableRotate = true;
      await goToFirst(2);
    }
  }
};
onMounted(() => {
  ({ scene, camera, renderer, controls, composer } = initThreeJS(
    threejsContainer.value
  ));

  // 加载模型
  loadModel("/person/human.fbx", (progress) => {
    progressValue.value = Math.floor(progress);
  }).then((model) => {
    personModel = model;
    LungGroup = model.getObjectByName("Lungs");
    // 定义材质缓存
    const materialMap = {
      body: bodyMaterial,
      Respiratoy: RespiratoyMaterial,
      Skeletal: SkeletalMaterial,
      Nerves1: NervesMaterial,
      Mammarygland: MammaryMaterial,
      Lungs: LungsMaterial,
    };

    // 遍历模型中的所有子物体并修改材质
    personModel.traverse((child) => {
      if (child.isMesh) {
        const name = child.name;

        if (name.startsWith("Lungs")) {
          // 优先处理 Lungs 部分
          if (name == "Lungs_L") {
            LungsL = child;
          } else if (name == "Lungs_R") {
            LungsR = child;
          }
          child.material = materialMap.Lungs;
          child.renderOrder = 2;
        } else if (name.startsWith("Mammarygland")) {
          // 处理 Mammarygland
          child.material = materialMap.Mammarygland;
          child.material.visible = isMan.value;
          child.renderOrder = 3;
        } else if (name.startsWith("Respiratoy")) {
          // 处理 Respiratoy
          child.material = materialMap.Respiratoy;
        } else if (name.startsWith("Skeletal")) {
          // 处理 Skeletal
          child.material = materialMap.Skeletal;
          child.renderOrder = 1;
        } else if (name.startsWith("Nerves1")) {
          // 处理 Nerves1
          child.material = materialMap.Nerves1;
        } else if (name.startsWith("body")) {
          // 默认处理 body
          child.material = materialMap.body;
        } else {
          // 其他情况
          child.material = materialMap.body;
        }
      }
    });

    scene.add(personModel);
    simulateCancerChange();
    // 设置模型的初始位置
    personModel.position.set(0, -1, 0);
    personModel.scale.set(0.01, 0.01, 0.01); // 缩放模型
    personModel.rotation.y = -Math.PI / 2;
    // 记录初始状态
    initialState = {
      cameraPosition: camera.position.clone(),
      personModelRotation: personModel.rotation.clone(),
      personModelPosition: personModel.position.clone(),
      lungGroupRotation: LungGroup.rotation.clone(),
      lungGroupPosition: LungGroup.position.clone(),
    };

    animate();
    isProgress.value = false;
    // if (personModel) {
    //   setupGUI(personModel, "personModel");
    // }
  });
  // 设置后期处理
  composer = setupPostProcessing(scene, camera, renderer);

  // 窗口大小改变处理
  window.addEventListener("resize", onWindowResize);
});

//人体模型和目标模型初始化
const goToFirst = (index) => {
  const {
    cameraPosition,
    personModelPosition,
    personModelRotation,
    lungGroupPosition,
    lungGroupRotation,
  } = initialState;
  return new Promise((resolve) => {
    // 设置模型的初始位置
    controls.reset();
    gsap.killTweensOf(LungGroup.rotation);
    let currentRotationY = personModel.rotation.y;
    let currentT = Math.floor(currentRotationY / (2 * Math.PI)); // 获取完整的周期数
    gsap.to(camera.position, {
      duration: 2,
      x: cameraPosition.x,
      y: cameraPosition.y,
      z: cameraPosition.z,
      ease: "power2.out",
    });
    gsap.to(personModel.position, {
      duration: 2,
      x: personModelPosition.x,
      y: personModelPosition.y,
      z: personModelPosition.z,
      ease: "power2.out",
      onComplete: resolve, // 动画完成时解决 Promise
    });
    if (index === 1) {
      gsap.to(personModel.rotation, {
        x: 0,
        z: 0,
        y: personModelRotation.y + currentT * 2 * Math.PI, // 目标旋转角度为初始角度 + 完整的周期数
        duration: 2,
        ease: "power2.out",
      });
    } else {
      console.log(2);
      gsap.to(personModel.rotation, {
        y: personModelRotation.y,
        x: 0,
        z: 0,
        duration: 2,
        ease: "power2.out",
      });
    }
    gsap.to(LungGroup.rotation, {
      duration: 2,
      x: lungGroupRotation.x,
      y: lungGroupRotation.y,
      z: lungGroupRotation.z,
      ease: "power2.out",
    });
    gsap.to(LungGroup.position, {
      duration: 2,
      z: lungGroupPosition.z,
      x: lungGroupPosition.x,
      y: lungGroupPosition.y,
      ease: "power2.out",
    });
  });
};
const simulateCancerChange = () => {
  // 获取左肺模型的包围盒
  const box = new THREE.Box3().setFromObject(LungsL);
  const center = box.getCenter(new THREE.Vector3());
  // 计算包围盒的对角线长度
  const size = box.getSize(new THREE.Vector3());
  diagonalLength = size.length(); // 包围盒对角线长度
  const uniforms = {
    time: { value: 0 },
    mouse: { value: new THREE.Vector2(0, 0) },
    resolution: {
      value: new THREE.Vector2(window.innerWidth, window.innerHeight),
    }, // 屏幕分辨率
  };
  //加载cell模型
  loadModel("/person/cell.fbx").then((model) => {
    sphere = model;
    sphere.scale.set(
      diagonalLength / 32,
      diagonalLength / 32,
      diagonalLength / 32
    ); // 缩放模型

    sphereMatiral = new THREE.ShaderMaterial({
      vertexShader: sunVertexShader, // 使用自定义的顶点着色器
      fragmentShader: sunFragmentShader, // 使用自定义的片段着色器
      uniforms,
      transparent: false, // 如果需要透明度，可以设置为 true
      side: THREE.DoubleSide, // 双面渲染
    });

    // 遍历 FBX 模型的每个子网格并应用材质
    sphere.traverse((child) => {
      if (child.isMesh) {
        child.material = sphereMatiral;
      }
    });

    // 设置球的位置为包围盒的中心
    sphere.position.copy(center);

    // 将球体添加到场景中
    scene.add(sphere);
    LungGroup.add(sphere);
  });
};
// 射线检测函数

const closeLayer = () => {
  isLayer.value = false;
};
//更新标签位置
const updateLabelPosition = (object, labelElement, camera) => {
  const vector = new THREE.Vector3();
  object.getWorldPosition(vector);
  vector.project(camera);
  const x = (vector.x * 0.5 + 0.5) * window.innerWidth;
  const y = (-vector.y * 0.5 + 0.1) * window.innerHeight;
  labelElement.style.left = `${x}px`;
  labelElement.style.top = `${y}px`;
  labelElement.style.transform = `translate(-50%, -50%)`;
};
function animate() {
  animationFrameId = requestAnimationFrame(animate);
  const delta = clock.getDelta(); // 获取时间差
  updateModelRotation(delta);
  updateSphereMaterial(delta);
  updateLabels();
  composer.render();
  renderer.render(scene, camera);
}

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}
function updateModelRotation(delta) {
  if (personModel && isRotating) {
    personModel.rotation.y += delta * 0.5; // 根据时间差更新旋转
  }
}

function updateSphereMaterial(delta) {
  if (sphere) {
    sphereMatiral.uniforms.time.value += delta * 0.05; // 根据时间差更新时间
  }
}

function updateLabels() {
  if (isLayer.value) {
    updateLabelPosition(LungGroup, threejsLayer.value, camera);
  }
}

onUnmounted(() => {
  // 清理事件监听器
  window.removeEventListener("resize", onWindowResize);
  isLayer.value = false;
  if (animationFrameId) {
    cancelAnimationFrame(animationFrameId); // 停止动画
  }
  renderer.dispose();
  composer.dispose();
});
</script>

<style lang="scss" scoped>
.threejs-container {
  position: relative;
  height: 100%;
  width: 100%;
  background: url(@/assets/bg/personBg.jpg) no-repeat center center;
  background-size: cover;
}

.threejs-layer {
  background: url(@/assets/bg/card_bg.png) no-repeat center center;
  background-size: contain;
}
</style>